package br.com.orion.sga.controller;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.Properties;

import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;

import org.primefaces.event.FileUploadEvent;
import org.primefaces.model.UploadedFile;

import br.com.orion.sga.exception.DaoException;
import br.com.orion.sga.exception.FileGenerateException;
import br.com.orion.sga.model.entities.Aluno;
import br.com.orion.sga.model.entities.Cidade;
import br.com.orion.sga.model.entities.Empresa;
import br.com.orion.sga.model.entities.PlanoPagamento;
import br.com.orion.sga.model.entities.Responsavel;
import br.com.orion.sga.model.entities.Uf;
import br.com.orion.sga.model.entities.Vencimento;
import br.com.orion.sga.service.AlunoService;
import br.com.orion.sga.service.CidadeService;
import br.com.orion.sga.service.EmpresaService;
import br.com.orion.sga.service.PlanoPagamentoService;
import br.com.orion.sga.service.ResponsavelService;
import br.com.orion.sga.service.UfService;
import br.com.orion.sga.service.VencimentoService;
import br.com.orion.sga.utils.CreateThumbnail;
import br.com.orion.sga.utils.GenerateCarne;
import br.com.orion.sga.utils.MessageHandler;
import br.com.orion.sga.utils.validators.PessoaFisica;
import br.com.orion.sga.utils.validators.interfaces.Pessoa;

@ManagedBean(name="addStudentController")
@ViewScoped
public class AddStudentController implements Serializable{

	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	
	private static final int PROPRIO_ALUNO = 1;
	private static final int STATE_MINAS_GERAIS = 1;
	private static final long ACADEMIA_ELITE_COMPANY = 1;
	private InputStream propertiesFile;
	private Properties sgaProperties;
	
	/*
	 * Services
	 */
	@ManagedProperty("#{alunoService}")
	private AlunoService alunoService;
	
	@ManagedProperty("#{vencimentoService}")
	private VencimentoService vencimentoService;
	
	@ManagedProperty("#{planoPagamentoService}")
	private PlanoPagamentoService planoPagamentoService;
	
	@ManagedProperty("#{responsavelService}")
	private ResponsavelService responsavelService;
	
	@ManagedProperty("#{ufService}")
	private UfService ufService;
	
	@ManagedProperty("#{cidadeService}")
	private CidadeService cidadeService;
	
	@ManagedProperty("#{empresaService}")
	private EmpresaService empresaService;
	
	
	/**
	 * Attributes of form to add new student
	 */
	private Aluno student;
	private List<Uf> listOfUf;
	private List<Cidade> listOfCities;
	private int isResponsible;
	private boolean enableResponsible;
	private List<Responsavel> listOfResponsibles;
	private List<Vencimento> listOfDaysToPayment;
	private List<PlanoPagamento> listOfPlanPayment;
	private UploadedFile photo;
	
	/**
	 * Construct
	 */
	
	@PostConstruct
	public void init() {
		
		File file = new File(System.getProperty("catalina.base") + "/webapps/sga/WEB-INF/classes/sga.properties");
		if (propertiesFile == null) {
			try {
				propertiesFile = new FileInputStream(file);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
		}
		
		if (sgaProperties == null) {
			sgaProperties = new Properties();
			try {
				sgaProperties.load(propertiesFile);//load properties file
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
		
	
	/**
	 * Method that will called when user click in Add Student button
	 */
	public void newStudent() {
		
		student = new Aluno();
		
		Vencimento vencimento = new Vencimento();
		student.setVencimento(vencimento);
		
		PlanoPagamento plainOfPayment = new PlanoPagamento();
		student.setPlanoPagamento(plainOfPayment);
		
		Responsavel responsible = new Responsavel();
		student.setResponsavel(responsible);
		
		populateCombobox();
		setDefaultValuesToOpenForm();
		
	}
	
	
	private void populateCombobox() {
		
		//Load all dayOfPayment storage on database
		listOfDaysToPayment = vencimentoService.listAll();
		
		//Load all planOfPayment storage on database
		listOfPlanPayment = planoPagamentoService.listAll();
		
		//load all responsibles storage on database
		listOfResponsibles = responsavelService.listAll();
		
		//load all states storage on database
		listOfUf = ufService.listAll();
		
	}
	

	private void setDefaultValuesToOpenForm() {
		//set default values
		isResponsible = PROPRIO_ALUNO; //set default to proprio aluno
		enableResponsible = true;//disable select responsible
		Cidade city = new Cidade();
		student.setCidade(city);
		Uf uf = ufService.getById(STATE_MINAS_GERAIS);
		student.getCidade().setUf(uf);
		ufChanged();
		
		/* Show the photo of perfil. In this case, show the photo  */
		student.setImagem("../" + sgaProperties.getProperty("dir_upload_photo_thumb") + "/default.png");
		
	}
	
	/**
	 * Methods that will listen the form of new student
	 */
	public void saveStudent() {
		
		/*
		 * Check if isResponsible is different to one case true the responsible is not the student
		 * So I have to create a new Responsible object and set its ID to set the relationship between 
		 * Responsible and Study
		 */
		Responsavel objResponsible = new Responsavel();
		if (isResponsible != PROPRIO_ALUNO) {
			objResponsible.setId(student.getResponsavel().getId()); //I think that is not necessary find the object with this id
		} else {
			objResponsible.setId(PROPRIO_ALUNO);//id of student self
		}
		student.setResponsavel(objResponsible);
		
		if (!formIsValid()) {
			return;
		}
		
		Empresa objEmpresa = empresaService.getById(ACADEMIA_ELITE_COMPANY);
//		objEmpresa.setId(ACADEMIA_ELITE_COMPANY);
		student.setEmpresas(objEmpresa);
		
		/**
		 * Check if it is need to create a carne
		 */
		if (student.getPlanoPagamento().getId() > 2) {
			student.setPlanoPagamento(planoPagamentoService.getById(student.getPlanoPagamento().getId()));
			GenerateCarne carne = new GenerateCarne(student);
			try {
				carne.generateCarne();
			} catch (FileGenerateException e) {
				MessageHandler.placeErrorMessage(e.getMessage());
			}
		}
		
		try {
			if (student.getId() > 0) {
				alunoService.update(student);
				MessageHandler.placeInfoMessage("Aluno atualizado com sucesso!");
			} else {
				alunoService.save(student);
				MessageHandler.placeInfoMessage("Aluno cadastrado com sucesso!");
			}
			//cleanFields();
		} catch (DaoException e) {
			MessageHandler.placeErrorMessage("Erro ao realizar operação!");
		}
	}
	
	
	
	public void loadStudent(Long id) {
		
		student = alunoService.getById(id);
		populateCombobox();
		ufChanged();
	}
	
	
	/**
	 * Methods that will listen the form of new student
	 * This method will be called when the uf field is changed
	 */
	public void ufChanged() {
		if (student.getCidade().getUf().getId() > 0) {
			listOfCities = cidadeService.getAllCitiesByUF(student.getCidade().getUf().getId());
		} else {
			listOfCities = null;
		}

	}
	
	
	/**
	 * Method that will listen the form of new student
	 * this methos will be called when the radioBox about if the student 
	 * will be the responsible or not is changed 
	 */
	public void changeCheckIsResponsible() {
		
		if (isResponsible != PROPRIO_ALUNO) {
			enableResponsible = false;
		} else {
			enableResponsible = true;
		}
	}
	
	
	public void handleFileUpload(FileUploadEvent event){
		
		photo = event.getFile();
		if (photo == null) {
			FacesMessage message = new FacesMessage("Erro ao realizar o upload da imagem.");
			FacesContext.getCurrentInstance().addMessage(null, message);
		} else {
			try {
				copyFile(photo.getFileName(), photo.getInputstream());
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			String dirUploadPhoto = System.getProperty("catalina.base") + "/webapps/sga/" + sgaProperties.getProperty("dir_upload_photo");
			String dirUploadPhotoThumb = System.getProperty("catalina.base") + "/webapps/sga/" + sgaProperties.getProperty("dir_upload_photo_thumb");
			
			Date today = new Date();
			long currentTime = today.getTime();
			CreateThumbnail.generateThumb(dirUploadPhoto, photo.getFileName(), dirUploadPhotoThumb, currentTime);
			student.setImagem("../" + sgaProperties.getProperty("dir_upload_photo_thumb") + currentTime + photo.getFileName());
			FacesMessage message = new FacesMessage("Sucesso ao realizar o upload da imagem.");
			FacesContext.getCurrentInstance().addMessage(null, message);
		}
		
	}
	
	private void copyFile(String fileName, InputStream in) {
        try{
			// write the inputStream to a FileOutputStream
			OutputStream out = new FileOutputStream(new File(System.getProperty("catalina.base") + "/webapps/sga/" + sgaProperties.getProperty("dir_upload_photo")
					+ fileName));

			int read = 0;
			byte[] bytes = new byte[1024];

			while ((read = in.read(bytes)) != -1) {
				out.write(bytes, 0, read);
			}

			in.close();
			out.flush();
			out.close();

			System.out.println("New file created!");
		} catch (IOException e) {
			System.out.println(e.getMessage());
		}
	}



	public boolean formIsValid() {
		
		if (student.getNome().isEmpty() || student.getNome().equals("") || student.getNome() == null) {
			MessageHandler.placeErrorMessage("Informe o nome do aluno(a)");
			return false;
		}
		
		if (!student.getCpf().equals("")) {
			boolean CPFIsValid = checkCPFIsValid();
			if (!CPFIsValid) {
				MessageHandler.placeErrorMessage("Informe um CPF Válido!");
				return false;
			} else {//check if user is editing the student register
				if (student.getId() == 0) { //check if a new student. If id  > 0 the user is editing student so does not needed check CPF because CPF is valid
					if (getExistingStudentByCPF(student.getCpf())) {
						MessageHandler.placeErrorMessage("CPF já registrado!");
						return false;
					}
				}
			}
		} else {
			if (student.getResponsavel().getId() == PROPRIO_ALUNO && student.getCpf().equals("")) {
				MessageHandler.placeErrorMessage("Informe um CPF!");
				return false;
			}
		}
		
		if (student.getCidade().getId() == 0) {
			MessageHandler.placeErrorMessage("Informe a cidade do aluno(a)");
			return false;
		}
		return true;
	}
	
	/**
	 * Validate the form
	 */
	private boolean checkCPFIsValid() {
		Pessoa pessoa = new PessoaFisica();
		boolean isValid = pessoa.validDocument(student.getCpf());
		return isValid;
	}
	
	
	/**
	 * get existing Responsible by CPF
	 * @param cpf
	 * @return
	 */
	private boolean getExistingStudentByCPF(String cpf) {
		
		try {
			alunoService.getByCPF(cpf);
			return true; //It was found a responsible with this same CPF on database
		} catch (DaoException e) {
			return false; //No found any responsible with this responsible
		}
	}
	
	
	/**
	 * GETTERS AND SETTERS
	 */
	public Aluno getStudent() {
		return student;
	}
	
	public void setStudent(Aluno student) {
		this.student = student;
	}
	
	public AlunoService getAlunoService() {
		return alunoService;
	}
	
	public void setAlunoService(AlunoService alunoService) {
		this.alunoService = alunoService;
	}
	
	public VencimentoService getVencimentoService() {
		return vencimentoService;
	}
	
	public void setVencimentoService(VencimentoService vencimentoService) {
		this.vencimentoService = vencimentoService;
	}
	
	public PlanoPagamentoService getPlanoPagamentoService() {
		return planoPagamentoService;
	}
	
	public void setPlanoPagamentoService(
			PlanoPagamentoService planoPagamentoService) {
		this.planoPagamentoService = planoPagamentoService;
	}
	
	public ResponsavelService getResponsavelService() {
		return responsavelService;
	}
	
	public void setResponsavelService(ResponsavelService responsavelService) {
		this.responsavelService = responsavelService;
	}
	
	public UfService getUfService() {
		return ufService;
	}
	
	public void setUfService(UfService ufService) {
		this.ufService = ufService;
	}
	
	public CidadeService getCidadeService() {
		return cidadeService;
	}
	
	public void setCidadeService(CidadeService cidadeService) {
		this.cidadeService = cidadeService;
	}
	
	public EmpresaService getEmpresaService() {
		return empresaService;
	}
	
	public void setEmpresaService(EmpresaService empresaService) {
		this.empresaService = empresaService;
	}

//	public String getName() {
//		return name;
//	}
//
//	public void setName(String name) {
//		this.name = name;
//	}
//
//	public String getAddress() {
//		return address;
//	}
//
//	public void setAddress(String address) {
//		this.address = address;
//	}
//
//	public String getNumber() {
//		return number;
//	}
//
//	public void setNumber(String number) {
//		this.number = number;
//	}
//
//	public String getDistrict() {
//		return district;
//	}
//
//	public void setDistrict(String district) {
//		this.district = district;
//	}
//
//	public int getState() {
//		return state;
//	}
//
//	public void setState(int state) {
//		this.state = state;
//	}
//
//	public int getCity() {
//		return city;
//	}
//
//	public void setCity(int city) {
//		this.city = city;
//	}
//
//	public Date getBirthday() {
//		return birthday;
//	}
//
//	public void setBirthday(Date birthday) {
//		this.birthday = birthday;
//	}
//
//	public Character getGender() {
//		return gender;
//	}
//
//	public void setGender(Character gender) {
//		this.gender = gender;
//	}
//
//	public String getCpf() {
//		return cpf;
//	}
//
//	public void setCpf(String cpf) {
//		this.cpf = cpf;
//	}
//
//	public String getRg() {
//		return rg;
//	}
//
//	public void setRg(String rg) {
//		this.rg = rg;
//	}
//
//	public String getPhone() {
//		return phone;
//	}
//
//	public void setPhone(String phone) {
//		this.phone = phone;
//	}
//
//	public String getMobilePhone() {
//		return mobilePhone;
//	}
//
//	public void setMobilePhone(String mobilePhone) {
//		this.mobilePhone = mobilePhone;
//	}
//
//	public Float getMensalidadeValue() {
//		return mensalidadeValue;
//	}
//
//	public void setMensalidadeValue(Float mensalidadeValue) {
//		this.mensalidadeValue = mensalidadeValue;
//	}
//
//	public Float getPersonalValue() {
//		return personalValue;
//	}
//
//	public void setPersonalValue(Float personalValue) {
//		this.personalValue = personalValue;
//	}

	public boolean isEnableResponsible() {
		return enableResponsible;
	}

	public void setEnableResponsible(boolean enableResponsible) {
		this.enableResponsible = enableResponsible;
	}

	public int getIsResponsible() {
		return isResponsible;
	}
	
	public void setIsResponsible(int isResponsible) {
		this.isResponsible = isResponsible;
	}

//	public int getResponsible() {
//		return responsible;
//	}
//
//	public void setResponsible(int responsible) {
//		this.responsible = responsible;
//	}
//
//	public int getDayOfPayment() {
//		return dayOfPayment;
//	}
//
//	public void setDayOfPayment(int dayOfPayment) {
//		this.dayOfPayment = dayOfPayment;
//	}
//
//	public int getPlanOfPayment() {
//		return planOfPayment;
//	}
//
//	public void setPlanOfPayment(int planOfPayment) {
//		this.planOfPayment = planOfPayment;
//	}

	public UploadedFile getPhoto() {
		return photo;
	}

	public void setPhoto(UploadedFile photo) {
		this.photo = photo;
	}
	
	public List<Vencimento> getListOfDaysToPayment() {
		return listOfDaysToPayment;
	}
	
	public void setListOfDaysToPayment(List<Vencimento> listOfDaysToPayment) {
		this.listOfDaysToPayment = listOfDaysToPayment;
	}
	
	public List<PlanoPagamento> getListOfPlanPayment() {
		return listOfPlanPayment;
	}
	
	public void setListOfPlanPayment(List<PlanoPagamento> listOfPlanPayment) {
		this.listOfPlanPayment = listOfPlanPayment;
	}
	
	public List<Responsavel> getListOfResponsibles() {
		return listOfResponsibles;
	}
	
	public void setListOfResponsibles(List<Responsavel> listOfResponsibles) {
		this.listOfResponsibles = listOfResponsibles;
	}
	
	public List<Uf> getListOfUf() {
		return listOfUf;
	}
	
	public void setListOfUf(List<Uf> listOfUf) {
		this.listOfUf = listOfUf;
	}
	
	public List<Cidade> getListOfCities() {
		return listOfCities;
	}
	
	public void setListOfCities(List<Cidade> listOfCities) {
		this.listOfCities = listOfCities;
	}
}
